package com.example.demo.controller;
import org.mindrot.jbcrypt.BCrypt;
import ch.qos.logback.core.util.StringUtil;
import ch.qos.logback.core.util.TimeUtil;
import com.example.demo.pojo.PageBean;
import com.example.demo.pojo.Result;
import com.example.demo.pojo.User;
import com.example.demo.pojo.UtilityBill;
import com.example.demo.service.MailService;
import com.example.demo.service.UserService;
import com.example.demo.utils.JwtUtil;
import com.example.demo.utils.ThreadLocalUtil;
import jakarta.validation.constraints.Pattern;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;
    @Autowired
    private MailService mailService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public boolean Authentication() {
        Map<String, Object> map = ThreadLocalUtil.get();
        String phonenumber = (String) map.get("phonenumber");
        User u = userService.findByphoneNumber(phonenumber);
        if (u.getUsertype() != 1) {
            return false;
        }
        return true;
    }

    public boolean UserStatus(String phonenumber){
        User u=userService.findByphoneNumber(phonenumber);
        if (u.getUserstatus()==0){
            return true;
        }
        return false;
    }


    @PostMapping("/register")
    public Result register(@Pattern(regexp = "^\\S{2,8}$") String realname, @Pattern(regexp = "^\\S{5,16}$") String password,@Pattern(regexp = "^\\S{3,20}$") String address,@Pattern(regexp = "^\\S{9,11}$") String phonenumber) {
        //
        User u = userService.findByphoneNumber(phonenumber);
        String hashedPassword = BCrypt.hashpw(password, BCrypt.gensalt());
        if (u == null) {
            userService.register(realname, hashedPassword,address,phonenumber);
            return Result.success();
        }
        else{
            return Result.error("用户名已存在");

        }
    }

    @PostMapping("/login")
    public Result<String> login(@Pattern(regexp = "^\\S{11,11}$") String phonenumber, @Pattern(regexp = "^\\S{5,16}$") String password) {

        User loginUser = userService.findByphoneNumber(phonenumber);

        if (loginUser == null) {
            return Result.error("用户不存在");
        }
        if(!UserStatus(phonenumber)){
            return Result.error("用户已停用");
        }
        if (loginUser.getPassword().equals(password)||BCrypt.checkpw(password, loginUser.getPassword())) {
            Map<String, Object> claims = new HashMap<>();
            claims.put("userid", loginUser.getUserid());
            claims.put("phonenumber",phonenumber );
            claims.put("usertype",loginUser.getUsertype());
            String token = JwtUtil.genToken(claims);
            ValueOperations<String, String> operations=stringRedisTemplate.opsForValue();
            operations.set(token,token,24, TimeUnit.HOURS);
            return Result.success(token);
        }

        return Result.error("密码错误");

    }

    @GetMapping("/userinfo")
    public Result<User> userinfo() {

        Map<String,Object> map= ThreadLocalUtil.get();
        String phonenumber = (String) map.get("phonenumber");
        User user = userService.findByphoneNumber(phonenumber);

        return Result.success(user);
    }

    @GetMapping("/r-userinfo")
    public Result<PageBean<User>> r_userinfo(@RequestParam(required = false) int pageNum,
                                             @RequestParam(required = false) int pageSize,
                                             @RequestParam(required = false) String realname,
                                            @RequestParam(required = false) String phonenumber,
                                             @RequestParam(required = false) String email,
                                             @RequestParam(required = false) String address ) {
        if(!Authentication()){
            return Result.error("权限不足");
        }
        PageBean<User> u = userService.findByinfo(realname,phonenumber,email,address, pageNum, pageSize);
        // 将查询到的水电费信息列表封装在一个成功的结果对象中返回。
        return Result.success(u);
    }

    @PostMapping("/sendArrearsMail")
    public Result sendArrearsMail(@RequestParam String phonenumber) {
        if(!Authentication()){
            return Result.error("权限不足");
        }
        User u=userService.findByphoneNumber(phonenumber);
        String email = u.getEmail();
        Double accountbalance = u.getAccountbalance();
        mailService.sendMail(email, "您的账户已欠费！", "您的账户已欠费： " + accountbalance+"元\n" + "请尽快充值缴费！");
        return Result.success();
    }

    @PostMapping("/updateStatus")
    public Result upadateStatus(@RequestParam String phonenumber) {
        if(!Authentication()){
            return Result.error("权限不足");
        }
        User u=userService.findByphoneNumber(phonenumber);
        int userid=u.getUserid();
        int userstatus = u.getUserstatus();
        if (userstatus == 1){
            userService.updateStatus(userid,0);
            return Result.success();
        }
        if (userstatus == 0){
            userService.updateStatus(userid,1);
            return Result.success();
        }
        return Result.error("更新失败");
    }


    /**
     * 更新用户信息
     *
     * @param user 用户对象，包含需要更新的用户信息
     * @return 更新操作结果，如果成功返回Result.success()，否则抛出异常
     */
    @PutMapping("/update")
    public Result update(@RequestBody User user) {
        Map<String,Object> map= ThreadLocalUtil.get();
        int userid = (int) map.get("userid");
        user.setUserid(userid);
        userService.update(user);
        return Result.success();
    }

    /**
     * 修改密码接口。
     * 通过@PatchMapping注解指定该方法处理的URL路径为/updatePwd，用于更新用户密码。
     * 使用@RequestBody注解将请求体中的数据绑定到一个Map对象paraes上，便于获取参数。
     *
     * @param paraes 包含旧密码、新密码和确认新密码的Map对象。
     * @return 返回一个Result对象，根据操作结果可能包含错误信息或操作成功的提示。
     */
    @PatchMapping("/updataPwd")
    public Result updataPwd(@RequestBody Map<String,String> paraes,@RequestHeader("Authorization") String token) {
        // 从请求体中获取旧密码、新密码和确认新密码
        String oldPwd = paraes.get("old_pwd");
        String newPwd = paraes.get("new_pwd");
        String rePwd = paraes.get("re_pwd");

        // 检查输入参数是否完整
        if(!StringUtils.hasLength(oldPwd)||!StringUtils.hasLength(newPwd)||!StringUtils.hasLength(rePwd)){
             return Result.error("请输入完整信息");
        }

        // 从线程本地存储中获取用户电话号码
        Map<String,Object> map= ThreadLocalUtil.get();
        String phonenumber = (String) map.get("phonenumber");
        // 根据电话号码查找登录用户
        User loginUser=userService.findByphoneNumber(phonenumber);
        // 验证旧密码是否正确
        if(!loginUser.getPassword().equals(oldPwd)){
            return Result.error("旧密码错误");
        }
        // 验证新密码和确认新密码是否一致
        if(!newPwd.equals(rePwd)){
            return Result.error("两次密码不一致");
        }

        // 更新用户密码
        userService.updatePwd(newPwd);
        // 返回操作成功的结果
        ValueOperations<String, String> operations=stringRedisTemplate.opsForValue();
        operations.getOperations().delete(token);

        return Result.success();

    }

    /**
     * 更新用户头像的接口。
     * 通过此接口，用户可以更新他们的头像。请求中需要提供新的头像的URL地址。
     * 方法接收URL经过@URL注解验证，确保URL的格式正确。
     * @param avatarurl 新头像的URL地址，用于更新用户头像。
     * @return 返回操作结果，如果操作成功，返回一个表示成功的Result对象。
     */
    @PatchMapping("/updateavatar")
    public Result updateavatar(@RequestParam @URL String avatarurl) {
        userService.updateavatar(avatarurl);
        return Result.success();
    }

    @PostMapping("/sendverificationCode")
    public Result sendverificationCode(@RequestParam String email) {
        // 根据手机号查找用户
        User u = userService.findByemail(email);
        if (u == null) {
            return Result.error("邮箱未找到对应的用户");
        }

        String password = u.getPassword();
        // 生成验证码
        String verificationCode = generateVerificationCode();
        // 发送验证码邮件
        mailService.sendMail(email, "重置密码验证码", "您的验证码是: " + verificationCode);
        // 验证码存储在Redis中，并设置过期时间5分钟
        ValueOperations<String, String> operations=stringRedisTemplate.opsForValue();
        operations.set("verificationCode", verificationCode, 300,TimeUnit.SECONDS);
        operations.set("email",email,300,TimeUnit.SECONDS);
        operations.set("password",password,300,TimeUnit.SECONDS);
        return Result.success();
    }

    /**
     * 该方法旨在接收验证代码，验证其是否正确。如果验证成功，它将从Redis中获取关联的电子邮件和密码，
     * 并通过邮件服务向用户发送密码信息，提示用户尽快修改密码。
     */
    @PostMapping("/findpassword")
    public Result findpassword(@RequestParam String verificationCode) {
        // 通过stringRedisTemplate操作Redis中的值。
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();

        // 从Redis中获取存储的验证码。
        String verificationcode = operations.get("verificationCode");

        // 验证用户输入的验证码与存储的验证码是否一致。
        if (verificationcode.equals(verificationCode)) {
            // 从Redis中获取存储的电子邮件和密码。
            String email = operations.get("email");
            String password = operations.get("password");

            // 使用邮件服务发送包含密码信息的邮件。
            mailService.sendMail(email, "找回密码", "您的密码为：" + password + "\n" + "请尽快修改密码！");

            // 返回成功结果。
            return Result.success();
        }

        // 如果验证码验证失败，返回错误结果。
        return Result.error("验证码错误！");
    }


    private String generateVerificationCode() {
        // 验证码的生成规则，生成6位随机数字
        return String.valueOf((int) (Math.random() * 900000 + 100000));
    }

}

